package service

import (
	"errors"
	uuid "github.com/satori/go.uuid"
	"gorm.io/gorm"
	"shop-common/library/env"
	"shop-common/library/loggerV2"
	"shop-common/library/variables"
	"shop-common/utils"
	"shop-common/utils/contextArgs"
	"shop-common/utils/pagehelper"
	"shop-common/utils/password"
	"shop-common/utils/queryWrapper"
	"shop-security/token"
	"shop-sys/cache"
	"shop-sys/model"
	"shop-sys/pkg/code"
	"shop-sys/pkg/constant"
	"shop-sys/pkg/request"
	"shop-sys/repository"
)

type ISysUserService interface {
	CheckUserExistCustom(pair *queryWrapper.WherePair) (bool, error)
	CreateUserAndUserRole(request *request.SysUserInsertRequest, internalId uint, roleIds []uint) error
	Login(request *request.SysUserLoginRequest, device *contextArgs.Device) (map[string]string, error)
	FindByIdPermsList(internalId uint) (permsList []string, err error)
	PageUser(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error)
	FindById(internalId uint) (*model.SysUser, error)
	FindOne(pair *queryWrapper.WherePair) (*model.SysUser, error)
	ListRoleIdByUserId(internalId uint) ([]uint, error)
	UpdateUserAndUserRole(request *request.SysUserUpdateRequest, internalId uint, roleIds []uint) (err error)
	UpdateUserStatus(sysUser *model.SysUser) error
	UpdateCacheUserRoles(userId string, roleIds []uint) error
	UpdatePasswordByUserId(internalId uint, newPassword string) error
	Delete(internalId uint) error
}

type SysUserService struct {
	db                    *gorm.DB
	sysUserRoleRepository repository.ISysUserRoleRepository
	sysUserRepository     repository.ISysUserRepository
}

func NewSysUserService(
) ISysUserService {
	return &SysUserService{
		db:                    variables.GormDB(),
		sysUserRoleRepository: repository.NewSysUserRoleRepository(),
		sysUserRepository:     repository.NewSysUserRepository(),
	}
}

func (s *SysUserService) CheckUserExistCustom(pair *queryWrapper.WherePair) (bool, error) {
	exist, err := s.sysUserRepository.CheckUserExist(s.db, pair)
	if err != nil {
		loggerV2.Errorf("checkUserExist by pair exist failed: err %v, pair %+v", err, pair)
		return exist, err
	}
	return exist, nil
}

//保存用户与用户角色关系
func (s *SysUserService) CreateUserAndUserRole(request *request.SysUserInsertRequest, internalId uint, roleIds []uint) error {
	salt := password.GenerateSalt()
	encryptPwd := password.GeneratePassword(request.Password, salt)
	sysUser := &model.SysUser{
		UserId:       uuid.NewV4().String(),
		Username:     request.Username,
		Password:     encryptPwd,
		PasswordSalt: salt,
		Email:        request.Email,
		Mobile:       request.Mobile,
		Status:       request.Status,
		ShopId:       constant.SHOP_ID,
	}

	if internalId > 0 {
		sysUser.CreateUserId = internalId
	}

	return s.db.Transaction(func(tx *gorm.DB) error {
		err := s.sysUserRepository.Create(tx, sysUser)
		if err != nil {
			loggerV2.Error(err)
			return err
		}

		//保存用户与角色关系
		if len(request.RoleIdList) == 0 {
			return nil
		}

		err = s.sysUserRoleRepository.CreateUserAndUserRole(tx, sysUser.Id, roleIds)
		if err != nil {
			loggerV2.Errorf("create sysUser and sysUserRole association failed: err %v, id %d, roleIds %d", err, sysUser.Id, roleIds)
			return err
		}
		return nil
	})
}

func (s *SysUserService) Login(request *request.SysUserLoginRequest, device *contextArgs.Device) (map[string]string, error) {
	user, err := s.sysUserRepository.FindOne(s.db, queryWrapper.Eq("username", request.Username))
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("findOne sysUser failed: err %v, username %s", err, request.Username)
		return nil, errors.New("查询用户数据失败！")
	}

	if user == nil || user.Id <= 0 {
		return nil, errors.New(code.StatusText(code.UserNotExist))
	}

	if user.Status == constant.SYS_USER_DISABLE {
		return nil, errors.New(code.StatusText(code.UserEnabled))
	}

	decodePwd := password.GeneratePassword(request.Password, user.PasswordSalt)
	if decodePwd != user.Password {
		return nil, errors.New(code.StatusText(code.UserPwdNotMatch))
	}

	roleIds, err := s.sysUserRoleRepository.FindListRoleIdByUserId(s.db, user.Id)
	if err != nil {
		loggerV2.Errorf("find by userId failed: err %v, userId %d", user.Id)
		return nil, errors.New("登录失败")
	}

	_, accessToken, err := token.GenerateAccessToken("admin-srv", user.UserId)
	if err != nil {
		loggerV2.Error(err)
		return nil, errors.New("登录失败")
	}

	result := map[string]string{
		"accessToken": accessToken,
	}

	if env.IsDevMode() {
		result["swaggerToken"] = "Bearer " + accessToken
	}

	go func() {
		// 存放登录信息
		_ = token.SetAuthCache(accessToken, "admin-srv", user.UserId, user.Id, user.ShopId, device)
		err = cache.SetUserOnlineRole(variables.RedisConn, user.UserId, roleIds)
	}()

	return result, nil
}

func (s *SysUserService) FindByIdPermsList(internalId uint) (permsList []string, err error) {
	sysUser, err := s.sysUserRepository.FindByIdUser(s.db, internalId)
	if err != nil {
		loggerV2.Errorf("find by userId sysUser failed: err %v, internalId %d", err, internalId)
		return
	}
	if sysUser == nil {
		// 用户不存在
		return
	}

	//todo  YamiSysUserDetailsServiceImpl.getUserPermissions
	//系统管理员，拥有最高权限
	if sysUser.Id == constant.SUPER_ADMIN_ID {
		permsList, err = s.sysUserRepository.FindByPerms(s.db, nil)
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			loggerV2.Errorf("find permsList failed: err %v, userId %d", err, sysUser.UserId)
			return
		}
	} else {
		permsList, err = s.sysUserRepository.FindByPerms(s.db, &queryWrapper.WherePair{Query: " ur.user_id = ? ", Args: []interface{}{sysUser.UserId}})
		if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
			loggerV2.Errorf("find by userId permsList failed: err %v, userId %d", err, sysUser.UserId)
			return
		}
	}

	if len(permsList) > 0 {
		permsList = utils.RemoveDuplicateElement(permsList)
	}
	return
}

/**
 * 根据当前shopId、keyword获取分页用户列表，根据createdAt排序
 * @return 所有用户分页列表
 */
func (s *SysUserService) PageUser(request *pagehelper.SearchPageRequest) (*pagehelper.Record, error) {
	paginator := pagehelper.New().SetOffset(request).SetFilter([]string{"user_id"}).
		Push(queryWrapper.Eq("shop_id", constant.SHOP_ID)).
		IsPush(request.Keyword != "", queryWrapper.Like("username", request.Keyword)).
		IsPush(request.Status > 0, queryWrapper.Eq("status", request.Status)).Paginator()

	count, err := s.sysUserRepository.Count(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find sysUser to count failed: err %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	if count == 0 {
		return paginator.Result(nil, count)
	}

	page, err := s.sysUserRepository.FindPage(s.db, paginator.Params)
	if err != nil {
		loggerV2.Errorf("find sysUser to page: err: %v, params %+v", err, paginator.Params)
		return paginator.Record, err
	}

	return paginator.Result(page, count)
}

/**
 * 根据用户id获取用户信息
 * @param userId
 * @return
 */
func (s *SysUserService) FindById(internalId uint) (*model.SysUser, error) {
	sysUser, err := s.sysUserRepository.FindByIdUser(s.db, internalId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("find by userId sysUser failed: err %v, internalId %d", err, internalId)
		return nil, err
	}
	return sysUser, err
}

func (s *SysUserService) FindOne(pair *queryWrapper.WherePair) (*model.SysUser, error) {
	sysUser, err := s.sysUserRepository.FindOne(s.db, pair)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("findOne by pair sysUser failed: err %v, pair %+v", err, pair)
		return nil, err
	}
	return sysUser, err
}

/**
 * 根据用户ID，获取角色ID列表
 * @param userId 用户id
 * @return 角色id列表
 */
func (s *SysUserService) ListRoleIdByUserId(internalId uint) ([]uint, error) {
	ids, err := s.sysUserRoleRepository.FindListRoleIdByUserId(s.db, internalId)
	if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
		loggerV2.Errorf("find by userId roleIds failed: err %v, internalId", err, internalId)
		return nil, err
	}
	return ids, nil
}

/**
 * 更新用户与用户角色关系
 * @param user
 */
func (s *SysUserService) UpdateUserAndUserRole(request *request.SysUserUpdateRequest, internalId uint, roleInternals []uint) (err error) {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 更新用户
		columns := map[string]interface{}{
			"status": request.Status,
		}

		if request.Password != "" && request.RepeatPassword != "" && request.Password == request.RepeatPassword {
			salt := password.GenerateSalt()
			encryptPwd := password.GeneratePassword(request.Password, salt)
			columns["password"] = encryptPwd
			columns["password_salt"] = salt
		}

		err = s.sysUserRepository.Updates(tx, internalId, columns)
		if err != nil {
			loggerV2.Error(err)
			return err
		}

		//先删除用户与角色关系
		err = s.sysUserRoleRepository.DeleteByUserId(tx, internalId)
		if err != nil {
			loggerV2.Errorf("delete by userId sysUser and sysUserRole association failed: err %v, internalId %d", err, internalId)
			return err
		}

		if len(request.RoleIdList) == 0 {
			return nil
		}

		//保存用户与角色关系
		err = s.sysUserRoleRepository.CreateUserAndUserRole(tx, internalId, roleInternals)
		if err != nil {
			loggerV2.Errorf("create sysUser and sysUserRole association failed: err %v, internalId %d", err, internalId)
			return err
		}
		return nil
	})
}

//修改cache的角色信息
func (s *SysUserService) UpdateCacheUserRoles(userId string, roleIds []uint) error {
	err := cache.SetUserOnlineRole(variables.RedisConn, userId, roleIds)
	if err != nil {
		loggerV2.Error(err)
		return err
	}
	return nil
}

/**
 * 更新用户状态
 * @param user
 */
func (s *SysUserService) UpdateUserStatus(sysUser *model.SysUser) error {
	columns := map[string]interface{}{
		"status": sysUser.Status,
	}

	err := s.sysUserRepository.Updates(s.db, sysUser.Id, columns)
	if err != nil {
		loggerV2.Error("updates by userId status failed: err %v, id %s", err, sysUser.UserId)
		return err
	}

	return nil
}

/**
 * 修改密码
 * @param userId       用户ID
 * @param newPassword  新密码
 */
func (s *SysUserService) UpdatePasswordByUserId(internalId uint, newPassword string) error {
	salt := password.GenerateSalt()
	encryptPwd := password.GeneratePassword(newPassword, salt)
	columns := map[string]interface{}{
		"password":      encryptPwd,
		"password_salt": salt,
	}

	err := s.sysUserRepository.Updates(s.db, internalId, columns)
	if err != nil {
		loggerV2.Error(err)
		return err
	}
	return nil
}

/**
 * 根据用户id删除用户
 * @param userIds
 */
func (s *SysUserService) Delete(internalId uint) error {
	return s.db.Transaction(func(tx *gorm.DB) error {
		// 删除用户
		if err := s.sysUserRepository.Delete(tx, internalId); err != nil {
			loggerV2.Errorf("delete by userId sysUser failed: err %v, internalId %d", err, internalId)
			return err
		}

		// 删除用户角色
		err := s.sysUserRoleRepository.DeleteByUserId(tx, internalId)
		if err != nil {
			loggerV2.Errorf("delete by userId sysUser and sysUserRole association failed: err %v, internalId %d", err, internalId)
			return err
		}
		return nil
	})
}
